Skip to content

[Fleet] Add namespace level customization for packages#262568

Merged
jillguyonnet merged 49 commits into
elastic:mainfrom
jillguyonnet:fleet/245181-integration-namespace-custom
May 6, 2026
Merged

[Fleet] Add namespace level customization for packages#262568
jillguyonnet merged 49 commits into
elastic:mainfrom
jillguyonnet:fleet/245181-integration-namespace-custom

Conversation

@jillguyonnet
Copy link
Copy Markdown
Member

@jillguyonnet jillguyonnet commented Apr 10, 2026

Summary

Closes #245181

Fleet currently supports user customization at the type level (e.g. logs@custom) and data-stream level (e.g. logs-system.application@custom), but not at the namespace level. Users managing multiple integrations under a shared namespace must configure each data stream individually.

This PR implements namespace level customization by adding opt-in per-namespace index templates.

This is an API-only solution for now. #264065 will implement UI changes.

Solution rationale

Fleet currently creates one base index template per data stream pattern defined by the integration, e.g. logs-system.application-*. This index templates applies to all matching data streams regardless of namespace, e.g. logs-system.application-production and logs-system.application-staging). This means that namespace-specific component templates (e.g. production@custom and staging@custom) cannot belong to that index template, otherwise they would compete with each other and affect all data streams, not just the relevant namespace.

In this change, Fleet creates a dedicated index template per data stream with a more specific index pattern and higher priority than the base template. This namespace template is a clone of the base template with {namespace}@custom added to composed_of. The base template is never modified.

Example:

Template index_patterns Priority
logs-system.application logs-system.application-* 200
logs-system.application@namespace.production logs-system.application-production* 250

Component templates in logs-system.application:

"composed_of": [
  "logs@mappings",
  "logs@settings",
  "logs-system.application@package",
  "logs@custom",
  "system@custom",
  "logs-system.application@custom",
  "ecs@mappings",
  ".fleet_globals-1",
  ".fleet_agent_id_verification-1"
],

Component templates in logs-system.application@namespace.production:

"composed_of": [
  "logs@mappings",
  "logs@settings",
  "logs-system.application@package",
  "logs@custom",
  "system@custom",
  "production@custom", // namespace level, between package and data stream
  "logs-system.application@custom",
  "ecs@mappings",
  ".fleet_globals-1",
  ".fleet_agent_id_verification-1"
],

Opt-in mechanism

Creating namespace templates for every namespace by default could potentially cause many templates to be created unnecessarily. To mitigate this, namespace level customization is opt-in and managed in the package installation:

{
  "item": {
    "name": "system",
    ...
    "installationInfo": {
      ...
      "namespace_customization_enabled_for": ["production"]
      }
    }
  }
}

Namespaces can be opted in by updating the package installation:

PUT kbn:/api/fleet/epm/packages/system
{
  "namespace_customization_enabled_for": ["production"]
}

Or using the new bulk API:

POST kbn:/api/fleet/epm/packages/_bulk_namespace_customization
{
  "packages": ["system", "nginx", "apache"],
  "enable":  ["production"],
  "disable": ["staging"]
}

Space awareness

Installation saved objects are shared across spaces, meaning the list of opted in namespaces for an installed package is cluster wide: any Kibana space that can see an integration sees the same opt-in list. Index templates and component templates are also cluster wide.

The present implementation attempts to mitigate the write-side of this using the allowed_namespace_prefixes per-space restriction mechanism in Fleet settings (which is already used to gate which namespaces a user can choose for agent/package policies in a given space).

When the user attempts to modify the list of opted in namespaces, it will be validated against allowed namespace prefixes if any (if none are set, there's no validation). For example, if prod namespace is allowed in space A, then from that space prod_eu and prod_us would be allowed, but not qa.

Performance and scaling

Namespace template creation and deletion is handled by an asynchronous task. This addresses risks of latency/timeouts and provides a built-in retry mechanism.

Testing

  1. Per-package opt-in creates namespace templates (existing policies)

    1. Install the System integration with a package policy using namespace production.

    2. Verify no namespace template exists yet:

    GET _index_template/logs-system.application@namespace.production
    

    should return 404.

    1. Opt in production:
    PUT kbn:/api/fleet/epm/packages/system
      {
        "namespace_customization_enabled_for": ["production"]
      }
    
    1. Wait a few seconds for the async task, then verify the namespace index template was created:
    GET _index_template/logs-system.application@namespace.production
    

    In particular, check:

    • index_patterns is ["logs-system.application-production*"]
    • priority is 250
    • composed_of includes production@custom
  2. Namespace template shows in Assets tab

    In Kibana UI → Integrations → System → Assets tab, confirm logs-system.application@namespace.production (and any other per-dataset variants) appear alongside other Fleet-managed assets.

  3. Namespace component templates are applied to their specific data streams only

    1. Create a production@customcomponent template, e.g.:
    PUT _component_template/production@custom
    {
      "template": {
        "settings": {
          "index.number_of_replicas": 2
        }
      }
    }
    
    1. Trigger a rollover if you already have data, or ingest a document to create backing indices, e.g.
    POST logs-system.application-production/_doc
    {
      "@timestamp": "2026-04-15T00:00:00Z",
      "message": "test document"
    }
    

    This should create the data stream and its first backing index automatically, using the logs-system.application@namespace.production index template (priority 250) rather than the base logs-system.application template (priority 200).
    3. Verify the production namespace data stream has number_of_replicas: 2:

    GET logs-system.application-production/_settings/index.number_of_replicas
    
    1. Verify a data stream in a different namespace does not have number_of_replicas: 2, confirming namespace isolation.
  4. Opt-out deletes index templates but keeps component templates

    1. Opt out production:
    PUT kbn:/api/fleet/epm/packages/system
      {
        "namespace_customization_enabled_for": []
      }
    
    1. Wait a few seconds for the async task, then verify the namespace index templates were deleted but the production@customcomponent template still exists.
  5. Uninstall cleans up namespace templates

    1. Opt production back in, namespace index template should exist.
    2. Delete all System policies, uninstall integration and verify the namespace index templates were deleted.
  6. Bulk endpoint

    1. Install System and Nginx and enable production and staging namespaces for both:
    POST kbn:/api/fleet/epm/packages/_bulk_namespace_customization
    {
      "packages": ["system", "nginx"],
      "enable": ["production", "staging"]
    }
    
    1. The response should be:
    {
      "items": [
        {
          "name": "system",
          "success": true,
          "namespace_customization_enabled_for": [
            "production"
          ]
        },
        {
          "name": "nginx",
          "success": true,
          "namespace_customization_enabled_for": [
            "production"
          ]
        }
      ]
    }
    
    1. Test combinations of enable and disable.
    2. Verify that passing the name of a non installed package results in error:
    {
      "items": [
        {
          "name": "system",
          "success": true,
          "namespace_customization_enabled_for": [
            "production"
          ]
        },
        {
          "name": "apache",
          "success": false,
          "error": "Package apache is not installed"
        }
      ]
    }
    
    1. Verify that it is not allowed to pass the same namespace in enable and disable:
    {
      "statusCode": 400,
      "error": "Bad Request",
      "message": "Namespaces must not appear in both enable and disable: production"
    }
    
  7. Space awareness

    1. Create a custom space and go to it.
    2. Configure allowed namespace prefixes in that space:
    PUT kbn:/api/fleet/space_settings
    { 
      "allowed_namespace_prefixes": ["prod"] 
    }
    
    1. Verify that you now can't opt in a namespace that doesn't match the allowed prefix:
    PUT kbn:/s/team-a/api/fleet/epm/packages/system
    { 
      "namespace_customization_enabled_for": ["staging"] 
    }
    

    Should result in:

    {
      "statusCode": 400,
      "error": "Bad Request",
      "message": "Cannot change namespace customization for: staging. Allowed prefixes in this space: prod"
    }
    
    1. Repeat with a matching namespace (e.g. prod_eu), it should work.
    2. Now change the allowed namespace prefixes to staging and try to opt out prod_eu (pass an empty array): it should reject with Cannot change namespace customization for: prod_eu. Allowed prefixes in this space: staging.
    3. Do similar checks with the bulk endpoint: note that if you pass multiple namespaces to opt in/out and at least one of them fails for a given package, the update will fail for this package.

Checklist

Check the PR satisfies following conditions.

Reviewers should verify this PR satisfies this list as well.

  • Any text added follows EUI's writing guidelines, uses sentence case text and includes i18n support
  • Documentation was added for features that require explanation or tutorials
  • Unit or functional tests were updated or added to match the most common scenarios
  • If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the docker list
  • This was checked for breaking HTTP API changes, and any breaking changes have been approved by the breaking-change committee. The release_note:breaking label should be applied in these situations.
  • Flaky Test Runner was used on any tests changed
  • The PR description includes the appropriate Release Notes section, and the correct release_note:* label is applied per the guidelines
  • Review the backport guidelines and apply applicable backport:* labels.

Identify risks

Risk of eventual consistency gap if package installation SO is saved (synchronous) but the async task fails to create/delete index templates.

Release note

Add opt-in namespace level customization to integrations.

@jillguyonnet jillguyonnet self-assigned this Apr 10, 2026
@jillguyonnet jillguyonnet added release_note:enhancement backport:skip This PR does not require backporting Team:Fleet Team label for Observability Data Collection Fleet team labels Apr 10, 2026
@jillguyonnet jillguyonnet force-pushed the fleet/245181-integration-namespace-custom branch from 83dbcb0 to 5047d41 Compare April 13, 2026 13:45
@jillguyonnet jillguyonnet force-pushed the fleet/245181-integration-namespace-custom branch from 5047d41 to a8be4ae Compare April 15, 2026 12:01
@jillguyonnet jillguyonnet changed the title [Fleet] Add <namespace>@custom component templates to package index templates [Fleet] Add namespace level customization for packages Apr 15, 2026
@jillguyonnet jillguyonnet marked this pull request as ready for review April 16, 2026 08:40
@jillguyonnet jillguyonnet requested review from a team as code owners April 16, 2026 08:40
@elasticmachine
Copy link
Copy Markdown
Contributor

Pinging @elastic/fleet (Team:Fleet)

@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp Bot commented Apr 16, 2026

Catch flakiness early (recommended)

Recommended before merge: run the flaky test runner against this PR to catch flakiness early.

Trigger a run with the Flaky Test Runner UI or post this comment on the PR:

/flaky ftrConfig:x-pack/platform/test/fleet_api_integration/config.space_awareness.ts:30

This check is experimental. Share your feedback in the #appex-qa channel.

Posted via Macroscope — Flaky Test Runner nudge

@jillguyonnet
Copy link
Copy Markdown
Member Author

/flaky ftrConfig:x-pack/platform/test/fleet_api_integration/config.space_awareness.ts:30

@kibanamachine
Copy link
Copy Markdown
Contributor

Flaky Test Runner

✅ Build triggered - kibana-flaky-test-suite-runner#11659

  • x-pack/platform/test/fleet_api_integration/config.space_awareness.ts x30

@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp Bot commented Apr 16, 2026

Approvability

Verdict: Needs human review

This PR introduces a new feature for namespace-level package customization, including new API endpoints, background tasks, and schema changes. Multiple unresolved review comments raise concerns about data integrity, performance, and error handling. The changes affect code owned by @elastic/fleet and require review by designated owners.

You can customize Macroscope's approvability policy. Learn more.

@jillguyonnet jillguyonnet requested a review from jsoriano April 16, 2026 08:43
@kibanamachine
Copy link
Copy Markdown
Contributor

Flaky Test Runner Stats

🎉 All tests passed! - kibana-flaky-test-suite-runner#11659

[✅] x-pack/platform/test/fleet_api_integration/config.space_awareness.ts: 30/30 tests passed.

see run history

@jillguyonnet
Copy link
Copy Markdown
Member Author

@elasticmachine merge upstream

@kibanamachine
Copy link
Copy Markdown
Contributor

💚 Build Succeeded

Metrics [docs]

Public APIs missing comments

Total count of every public API that lacks a comment. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats comments for more detailed information.

id before after diff
fleet 1727 1729 +2

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
fleet 204.2KB 204.3KB +74.0B
Unknown metric groups

API count

id before after diff
fleet 1935 1938 +3

History

cc @jillguyonnet

@criamico criamico self-assigned this May 4, 2026
@criamico
Copy link
Copy Markdown
Member

criamico commented May 5, 2026

@elasticmachine merge upstream

@criamico criamico requested a review from jeramysoucy May 5, 2026 07:43
Copy link
Copy Markdown
Member

@vishaangelova vishaangelova left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of small suggestions, otherwise LGTM!

Comment thread x-pack/platform/plugins/shared/fleet/server/types/rest_spec/epm.ts Outdated
criamico and others added 3 commits May 5, 2026 10:53
Co-authored-by: Visha Angelova <91186315+vishaangelova@users.noreply.github.com>
Co-authored-by: Visha Angelova <91186315+vishaangelova@users.noreply.github.com>
@jeramysoucy jeramysoucy removed their request for review May 5, 2026 09:46
@criamico criamico requested a review from darnautov May 5, 2026 09:53
Comment thread x-pack/platform/plugins/shared/fleet/server/types/rest_spec/epm.ts Fixed
@criamico
Copy link
Copy Markdown
Member

criamico commented May 6, 2026

@elasticmachine merge upstream

@kibanamachine
Copy link
Copy Markdown
Contributor

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] Jest Integration Tests #8 / step level timeout should have execution duration close to configured timeout value

Metrics [docs]

Public APIs missing comments

Total count of every public API that lacks a comment. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats comments for more detailed information.

id before after diff
fleet 1727 1729 +2

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
fleet 203.9KB 204.0KB +74.0B
Unknown metric groups

API count

id before after diff
fleet 1935 1938 +3

History

cc @criamico @jillguyonnet

@jillguyonnet jillguyonnet merged commit c6253db into elastic:main May 6, 2026
32 checks passed
@jillguyonnet jillguyonnet deleted the fleet/245181-integration-namespace-custom branch May 11, 2026 08:25
jillguyonnet added a commit that referenced this pull request May 19, 2026
## Summary

Closes #264065

This PR adds the following UI:
* Input for managing namespaces enabled for customization for a given
package in the package's Settings tab
* Toggle for enabling/disabling a namespace for customization when
creating/editing a package policy

Note: release notes are included in
#262568

### Testing

1. Set up some allowed namespace prefixes for the space, e.g.:
   ```
   PUT kbn:/api/fleet/space_settings
   {
       "allowed_namespace_prefixes": ["prod", "qa"]
   }
   ```
2. Integration detail Settings tab
   * Pick an integration (e.g. System)
   * Check that the "Namespace customization" section is not rendered
   * Install the integration
   * The "Namespace customization" section should be rendered
* Try to add a namespace that doesn't match the allowed prefixes (e.g.
`staging`): it should be rejected
* Add a namespace that matches the allowed prefixes (e.g. `prod1`): it
should be allowed and a toast notification should confirm
* Check that the namespace was correctly opted in via API (`GET
/api/fleet/epm/packages/<pkg>`,
`installationInfo.namespace_customization_enabled_for`)
   * Also test namespace opt out
3. Package policy editor (create flow)
   * Create a package policy (add the integration)
* Open "Advanced options": there should be a toggle labelled "Enable
namespace-level customization" that defaults to disabled
* Add a namespace that matches the allowed prefixes and is not already
opted in (e.g. `prod2`), enable the toggle: after saving the policy,
this namespace should be added to the list of opted in namespaces for
this package
* Create another package policy with the same namespace (`prod2`), but
this time leave the toggle disabled: there should be a warning that
doing this will opt out the namespace, affecting the previously created
package policy
* Create another package policy with a namespace that is not opted in
(e.g. `prod3`), leave the toggle disabled
* Create another package policy with the same namespace (`prod3`) and
enable the toggle: there should be a warning that doing this will opt in
the namespace, affecting the previously created package policy
4. Package policy editor (edit flow)
* For integration packages, it should be possible to change the
namespace and whether it is opted in for the package
* For input packages, the namespace cannot be changed after creation but
it should be possible to change whether it is opted in for the package

### Screenshots

<img width="1917" height="878" alt="Screenshot 2026-05-13 at 15 52 26"
src="https://github.com/user-attachments/assets/7b667f02-6fc4-4148-8b96-b665fc67a9b4"
/>

<img width="1917" height="826" alt="Screenshot 2026-05-13 at 15 53 19"
src="https://github.com/user-attachments/assets/d7b4a969-3911-4b77-8f96-d52b982f0f3b"
/>

<img width="1917" height="671" alt="Screenshot 2026-05-13 at 15 55 11"
src="https://github.com/user-attachments/assets/9373c64b-f7ce-4a4f-bf51-db0805214aca"
/>

<img width="1917" height="666" alt="Screenshot 2026-05-13 at 15 55 36"
src="https://github.com/user-attachments/assets/d0f45b43-ee21-407c-beb0-396cf1880405"
/>

<img width="1917" height="666" alt="Screenshot 2026-05-13 at 15 56 02"
src="https://github.com/user-attachments/assets/ba040ef0-2cde-415e-a4ba-347bcdadc7c7"
/>

### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [ ] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [ ] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.

### Identify risks

Does this PR introduce any risks? For example, consider risks like hard
to test bugs, performance regression, potential of data loss.

Describe the risk, its severity, and mitigation for each identified
risk. Invite stakeholders and evaluate how to proceed before merging.

- [ ] [See some risk
examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx)
- [ ] ...

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting release_note:enhancement Team:Fleet Team label for Observability Data Collection Fleet team v9.5.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Fleet] Add support for customizing integration datastream at the namespace@custom level of granularity